package org.walklink.agent;

import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;
import org.walklink.agent.plugin.IPlugin;
import org.walklink.agent.plugin.InterceptPoint;
import org.walklink.agent.plugin.PluginFactory;
import org.walklink.core.client.ClientInitializer;
import org.walklink.core.config.ConfigInitializer;

import java.lang.instrument.Instrumentation;
import java.util.List;

/**
 * javaagent增强客户端
 *
 * @author lidishan
 */
public class WalklinkAgent {

    /**
     * JVM 首先尝试在代理类上调用以下方法
     * @param agentArgs 代理参数
     * @param inst Instrumentation
     */
    public static void premain(String agentArgs, Instrumentation inst) {
        // 1 初始化配置
        ConfigInitializer.initConfig(agentArgs);

        // 2 初始化连接客户端
        ClientInitializer.init();

        System.out.println("==========================================================\r\n");
        System.out.println("-> start up walklink apm==================================\r\n");
        System.out.println("==========================================================\r\n");

        AgentBuilder agentBuilder = initAgent();

        agentBuilder.with(initListener()).installOn(inst);

    }

    public static AgentBuilder initAgent() {
        AgentBuilder agentBuilder = new AgentBuilder.Default();

        List<IPlugin> pluginGroup = PluginFactory.pluginGroup;
        for (IPlugin plugin : pluginGroup) {
            InterceptPoint[] interceptPoints = plugin.buildInterceptPoint();
            for (InterceptPoint point : interceptPoints) {
                AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, javaModule) -> {
                    // 添加构建属性
                     builder = builder.visit(Advice.to(plugin.adviceClass()).on(point.buildMethodsMatcher()));
//                    builder = builder
//                            .method(ElementMatchers.<MethodDescription>any()) // 拦截任意方法
//                            .intercept(MethodDelegation.to(InterceptPoint.class)); // 委托
                    return builder;
                };
                agentBuilder = agentBuilder
                        .type(point.buildTypesMatcher())
                        .transform(transformer).asDecorator();
            }
        }

        return agentBuilder;
    }

    public static AgentBuilder.Listener initListener() {
        //监听
        return new AgentBuilder.Listener() {
            @Override
            public void onDiscovery(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) {
                System.out.println("onDiscovery");
            }

            @Override
            public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b, DynamicType dynamicType) {
                System.out.println("onTransformation：" + typeDescription);
            }

            @Override
            public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b) {
                System.out.println("onIgnored");
            }

            @Override
            public void onError(String s, ClassLoader classLoader, JavaModule javaModule, boolean b, Throwable throwable) {
                System.out.println("onError");
            }

            @Override
            public void onComplete(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) {
                System.out.println("onComplete");
            }
        };
    }

}